package com.joyd.joydlib.io

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString
import java.util.concurrent.TimeUnit

/**
 * WebSocket的封装类，实现断线重连、状态管理、暂停和恢复功能
 *
 * @param url WebSocket服务器地址
 * @param client 可选的OkHttpClient实例，用于自定义配置
 */
class WebSocketClient(
    private val url: String,
    client: OkHttpClient? = null
) {
    // 创建客户端，设置合理的超时时间
    private val client: OkHttpClient = client ?: OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .build()

    // WebSocket实例
    private var webSocket: WebSocket? = null

    // 重连相关配置
    private var reconnectEnabled = true
    private var maxReconnectAttempts = 10
    private var currentReconnectAttempt = 0
    private var baseReconnectDelayMs = 1000L // 1秒
    private var maxReconnectDelayMs = 30000L // 30秒
    private var reconnectJob: Job? = null

    // 状态管理
    private val _connectionState = MutableStateFlow<ConnectionState>(ConnectionState.Disconnected)
    val connectionState: StateFlow<ConnectionState> = _connectionState.asStateFlow()

    // 消息回调
    private var messageCallback: ((String) -> Unit)? = null
    private var binaryMessageCallback: ((ByteString) -> Unit)? = null
    private var stateChangeCallback: ((ConnectionState) -> Unit)? = null
    private var errorCallback: ((Throwable?) -> Unit)? = null

    // 协程作用域
    private val scope = CoroutineScope(Dispatchers.IO)

    /**
     * WebSocket连接状态
     */
    sealed class ConnectionState {
        object Disconnected : ConnectionState()
        object Connecting : ConnectionState()
        object Connected : ConnectionState()
        object Paused : ConnectionState()
    }

    /**
     * 启动WebSocket连接
     */
    fun connect() {
        if (webSocket != null) return

        reconnectEnabled = true
        currentReconnectAttempt = 0
        _connectionState.value = ConnectionState.Connecting

        val request = Request.Builder()
            .url(url)
            .header("Sec-WebSocket-Protocol", "device-phone")
            .build()
        val listener = object : WebSocketListener() {
            override fun onOpen(webSocket: WebSocket, response: Response) {
                this@WebSocketClient.webSocket = webSocket
                _connectionState.value = ConnectionState.Connected
                currentReconnectAttempt = 0
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                messageCallback?.invoke(text)
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                binaryMessageCallback?.invoke(bytes)
            }

            override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                webSocket.close(code, reason)
            }

            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                this@WebSocketClient.webSocket = null
                _connectionState.value = ConnectionState.Disconnected
                attemptReconnect()
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                this@WebSocketClient.webSocket = null
                _connectionState.value = ConnectionState.Disconnected
                errorCallback?.invoke(t)
                attemptReconnect()
            }
        }

        webSocket = client.newWebSocket(request, listener)
    }

    /**
     * 断开WebSocket连接
     */
    fun disconnect() {
        reconnectEnabled = false
        reconnectJob?.cancel()
        webSocket?.close(1000, "Normal closure")
        webSocket = null
    }

    /**
     * 暂停WebSocket连接
     */
    fun pause() {
        if (_connectionState.value == ConnectionState.Connected) {
            _connectionState.value = ConnectionState.Paused
            disconnect()
        }
    }

    /**
     * 恢复WebSocket连接
     */
    fun resume() {
        if (_connectionState.value == ConnectionState.Paused) {
            connect()
        }
    }

    /**
     * 发送文本消息
     */
    fun send(text: String): Boolean {
        return webSocket?.send(text) ?: false
    }

    /**
     * 发送二进制消息
     */
    fun send(bytes: ByteString): Boolean {
        return webSocket?.send(bytes) ?: false
    }

    /**
     * 设置文本消息回调
     */
    fun setOnMessageCallback(callback: ((String) -> Unit)?) {
        messageCallback = callback
    }

    /**
     * 设置二进制消息回调
     */
    fun setOnBinaryMessageCallback(callback: ((ByteString) -> Unit)?) {
        binaryMessageCallback = callback
    }

    /**
     * 设置连接状态变化回调
     */
    fun setOnStateChangeCallback(callback: ((ConnectionState) -> Unit)?) {
        stateChangeCallback = callback
    }

    /**
     * 设置错误回调
     */
    fun setOnErrorCallback(callback: ((Throwable?) -> Unit)?) {
        errorCallback = callback
    }

    /**
     * 设置重连配置
     */
    fun setReconnectConfig(
        maxAttempts: Int = 10,
        baseDelayMs: Long = 1000L,
        maxDelayMs: Long = 30000L
    ) {
        maxReconnectAttempts = maxAttempts
        baseReconnectDelayMs = baseDelayMs
        maxReconnectDelayMs = maxDelayMs
    }

    /**
     * 尝试重连
     */
    private fun attemptReconnect() {
        if (!reconnectEnabled || currentReconnectAttempt >= maxReconnectAttempts) {
            return
        }

        currentReconnectAttempt++
        val delayMs = calculateExponentialDelay(currentReconnectAttempt)

        reconnectJob = scope.launch {
            delay(delayMs)
            connect()
        }
    }

    /**
     * 计算指数退避延迟时间
     */
    private fun calculateExponentialDelay(attempt: Int): Long {
        // 指数退避算法：baseDelay * (2^(attempt-1))，但不超过maxDelay
        val delay = baseReconnectDelayMs * Math.pow(2.0, (attempt - 1).toDouble()).toLong()
        return minOf(delay, maxReconnectDelayMs)
    }

    /**
     * 清理资源
     */
    fun release() {
        disconnect()
        messageCallback = null
        binaryMessageCallback = null
        stateChangeCallback = null
        errorCallback = null
    }
}